package readwritelock;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 读写锁使用案例
 *
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/09/12 上午 10:26
 */
public class ReadWriteLockDemo {

//    public static void main(String[] args) {
//        //资源对象
//        MyResource resource = new MyResource();
//
//        //2个读线程
//        for (int i = 1; i <= 5; i++) {
//            new Thread(() -> {
//                resource.read();
//            }, "reader" + i).start();
//        }
//
//        //5个写线程
//        for (int i = 1; i <= 5; i++) {
//            new Thread(() -> {
//                resource.write(randomStr());
//            }, "writer" + i).start();
//        }
//
//        //5个读线程
//        for (int i = 6; i <= 10; i++) {
//            new Thread(() -> {
//                resource.read();
//            }, "reader" + i).start();
//        }
//
//        //5个写线程
//        for (int i = 6; i <= 10; i++) {
//            new Thread(() -> {
//                resource.write(randomStr());
//            }, "writer" + i).start();
//        }
//    }

    public static void main(String[] args) {
        MyResource resource = new MyResource();
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 10; i1++) {
                    resource.read();
                }
            }).start();
        }
        new Thread(()->{
            for (int i1 = 0; i1 < 10; i1++) {
                resource.write(randomStr());
            }
        }).start();
    }

    private static String randomStr() {
        int x = ThreadLocalRandom.current().nextInt(26);
        char newCh = (char) ('a' + x);
        return "" + newCh;
    }
}

class MyResource {
    /**
     * StringBuilder本身不是线程安全的
     */
    private final StringBuilder sb = new StringBuilder();
    /**
     * 读写锁
     */
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void read() {
        //获取读锁
        Lock readLock = readWriteLock.readLock();
        //读锁加锁
        readLock.lock();
        try {
            System.out.println(threadTag() + "当前字符串内容为：" + sb);
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            readLock.unlock();
        }


    }

    public void write(String msg) {
        //获取写锁
        Lock writeLock = readWriteLock.writeLock();
        //加写锁
        writeLock.lock();
        try {
            System.out.println(threadTag() + "向字符串写入内容：" + msg);
            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sb.append(msg);
        } finally {
            writeLock.unlock();
        }
    }

    public int length() {
        return sb.length();
    }

    private String threadTag() {
        return "[" + System.currentTimeMillis() + "]" + " [" + Thread.currentThread().getName() + "]";
    }

}


